#pragma once
#include "dataManger.hpp"
#include "config.hpp"
#include "util.hpp"
#include "hotManger.hpp"
#include "httplib.h"
#include <thread>
#include <ctime>
#include "userManger.hpp"
namespace Cloud
{
    // 登录模块:
    // 完成用户认证和注册
    class Login
    {
    public:
        Login(const std::string user, const std::string &pswd) : _username(user), _password(pswd), _mysql()
        {
            std::string username = Config::getInstance().userName();
            std::string password = Config::getInstance().password();
            std::string database = Config::getInstance().database();
            std::string host = Config::getInstance().host();
            uint16_t port = Config::getInstance().port();
            _mysql.connect(username, password, database, host, port);
        }
        const std::string &username() const { return _username; };
        const std::string &password() const { return _password; };
        bool login()
        {
            // 从数据库中读取数据验证
            std::string sql = "select * from ";
            sql += Config::getInstance().userTableName();
            sql += std::string(" where username=") + "'" + _username + "'" + " and password=" + "'" + _password + "'";
            _mysql.query(sql);
            MYSQL_RES *res;
            _mysql.result(&res);
            MYSQL_ROW row;
            (row = _mysql.fetchRow(res));
            bool ret = (row != nullptr ? true : false);
            mysql_free_result(res);
            return ret;
        }
        bool enroll()
        {
            // 构建用户节点
            Cloud::UserNode u1(_username, _password);
            return Cloud::UserManger::getInstance().insert(u1);
        }

    private:
        std::string _username;
        std::string _password;
        MysqlManger _mysql;
    };

    // 完成业务处理
    class Server
    {
        // 切割
        static bool spit(const std::string &str, std::vector<std::string> *array)
        {
            int pos1 = str.find("username");
            int pos2 = str.find("password");
            int pos3 = str.find(";");
            if (pos1 == std::string::npos || pos3 == std::string::npos || pos2 == std::string::npos)
                return false;
            pos1 += std::string("username").size() + 1;
            pos2 += std::string("password").size() + 1;
            if (pos1 < pos2)
            {
                (*array)[0] = std::string(str.begin() + pos1, str.begin() + pos3);
                (*array)[1] = std::string(str.begin() + pos2, str.end());
            }
            else
            {
                (*array)[0] = std::string(str.begin() + pos1, str.end());
                (*array)[1] = std::string(str.begin() + pos2, str.begin() + pos3);
            }
            return true;
        }
        // 对用户cookie中的字段进行验证或注册
        static void LoginFun(const httplib::Request &req, httplib::Response &res)
        {
            std::cout << "login" << std::endl;
            if (req.has_param("username") == false || req.has_param("password") == false)
            {
                res.status = 404;
                std::cout << __FILE__ << ":" << __LINE__ << ":" << 404 << std::endl;
                return;
            }

            std::string username = req.get_param_value("username");
            std::string password = req.get_param_value("password");
            Login lo(username, password);
            std::cout << __LINE__ << std::endl;
            std::string path = req.path;
            std::cout << "path " << path << std::endl;
            int pos = path.find_last_of("/");
            int pos2 = path.find_last_of("/", pos - 1);
            std::cout << __LINE__ << std::endl;
            std::cout << "pos " << pos << "pos2 " << pos2 << std::endl;
            std::string str(path.begin() + pos2 + 1, path.begin() + pos);
            std::cout << __LINE__ << std::endl;

            if (str == "login")
            {
                if (lo.login() == false)
                {
                    res.status = 404;
                    return;
                }
                else
                {
                    // 验证通过
                    // 用户节点信息不存在才为,为用户构建userNode节点,并将其插入管理者,
                    UserNode user;
                    if (UserManger::getInstance().getOneByUsername(username, &user) == false)
                    {
                        UserNode tmp(username, password);
                        UserManger::getInstance().insert(tmp);
                    }
                }
            }
            else
                lo.enroll();
            // 验证通过，给客户端一个永久重定向
            //  4. 设置键值对
            res.status = 301;
            res.set_header("Location", std::string("http://") + Config::getInstance().serverIp() + std::string(":") + std::to_string(Config::getInstance().serverPort()) + "/showList/");
            res.set_header("Set-Cookie", std::string("password=") + password + "; " + "path=/");
            res.set_header("Set-Cookie", std::string("username=") + username + "; " + "path=/");
        }
        static void BackupFun(const httplib::Request &req, httplib::Response &res)
        {
            // 1. 先验证身份
            std::vector<std::string> vs;
            vs.resize(2);
            if (req.has_header("Cookie") == false || (spit(req.get_header_value("Cookie"), &vs) == false))
            {
                res.status = 404;
                return;
            }
            Login lo(vs[0], vs[1]);
            UserNode user;
              // 用户名或密码错误
            if(lo.login()==false)
            {
                 res.status = 404;
                return;
            }
            if( UserManger::getInstance().getOneByUsername(vs[0], &user) == false){

                UserNode u1(vs[0],vs[1]);
                Cloud::UserManger::getInstance().insert(u1);
                user=u1;
            }
            // 身份通过开始业务处理
            //  1. 先判断请求中携带的内容是不是文件数据;
            if (req.has_file("file") == false)
            {
                res.status = 404;
                return;
            }
            const auto &file = req.get_file_value("file");
            std::string realPath = user.backupPath + file.filename;
            // 2. 将文件数据进行备份
            fileUtil f1(realPath);
            f1.setContent(file.content);
            // 3. 将备份信息添加进数据管理模块
            blackupFileMsg b1(realPath,user.compressPath+file.filename+Cloud::Config::getInstance().suffixName());
            user.data->insert(b1);
            // 4. 构建响应
            res.status = 200;
        }
        static std::string timeToString(time_t t)
        {
            return ctime(&t);
        }
        static void ShowListFun(const httplib::Request &req, httplib::Response &res)
        {
            // 1. 先验证身份
            std::vector<std::string> vs;
            vs.resize(2);
            if (req.has_header("Cookie") == false || (spit(req.get_header_value("Cookie"), &vs) == false))
            {
                res.status = 404;

                return;
            }
            Login lo(vs[0], vs[1]);
            UserNode user;
            // 用户名或密码错误
            if(lo.login()==false)
            {
                 res.status = 404;
                return;
            }
            if( UserManger::getInstance().getOneByUsername(vs[0], &user) == false){

                UserNode u1(vs[0],vs[1]);
                Cloud::UserManger::getInstance().insert(u1);
                user=u1;
            }
            // 1. 先获取所有备份文件信息;
            std::vector<blackupFileMsg> array;
            user.data->getAll(&array);
            std::string &body = res.body;
            body += "<html><head><meta charset='UTF-8'><title>Download</title></head><body><h1>Download</h1><table>";
            // 2. 将这些备份文件信息组成html语句
            for (auto &e : array)
            {
                body += "<tr>";
                body += "<td><a href='" + (e._url) + "'>" + (e._filename) + "</a></td>";
                body += "<td align='right'> " + (timeToString(e._mTime)) + "</td>";
                body += "<td align='right'> " + (e._fsize < 1024 ? (std::string(" ") + std::to_string(e._fsize) + " bytes ") : (std::to_string(e._fsize / 1024) + " k ")) + "</td>";
                body += "</tr>";
            }
            body += "</table></body></html>";
            // 3. 构建响应
            res.status = 200;
            // 4. 设置键值对
            res.set_header("Content-Type", "text/html");
            // res.set_header("Set-Cookie", std::string("password=") + vs[1] + "; " + "Path=/; " + "SameSite=None");
            // res.set_header("Set-Cookie", std::string("username=") + vs[0] + "; " + "Path=/; " + "SameSite=None");
        }
        static std::string getETag(const blackupFileMsg &e)
        {
            return e._filename + std::to_string(e._fsize) + std::to_string(e._mTime);
        }

        static void DownloadFun(const httplib::Request &req, httplib::Response &res)
        {

            // 1. 先验证身份
            std::vector<std::string> vs;
            vs.resize(2);
            if (req.has_header("Cookie") == false || (spit(req.get_header_value("Cookie"), &vs) == false))
            {
                res.status = 404;
                std::cout<<__LINE__<<"出现404"<<std::endl;
                return;
            }
            Login lo(vs[0], vs[1]);
            UserNode user;
            // 用户名或密码错误
            if(lo.login()==false)
            {
                 res.status = 404;
                std::cout<<__LINE__<<"出现404"<<std::endl;

                return;
            }
            if( UserManger::getInstance().getOneByUsername(vs[0], &user) == false){

                UserNode u1(vs[0],vs[1]);
                Cloud::UserManger::getInstance().insert(u1);
                user=u1;
            }
            // 1. 提取url
            std::string url = req.path;
            // 2. 检测url对应的备份文件信息是否存在
            blackupFileMsg b1;
            if (user.data->getBackupFileMsgByURL(url, &b1) == false)
            {
                res.status = 404;
                std::cout<<__LINE__<<"出现404"<<std::endl;
                return;
            }
            // 3. 判断备份文件是否被压缩
            std::cout<<(b1._compressFlag?"true":"false")<<std::endl;
            if (b1._compressFlag)
            {
                fileUtil f1(b1._compressPath);
                if (!f1.exists())
                {
                    res.status = 404;
                    return;
                }

                fileUtil f2(b1._realPath);
                
                f1.unCompress(b1._realPath);
                if(f2.exists()) 
                {
                    std::cout<<b1._realPath<<"存在"<<std::endl;
                }
                else{
                    std::cout<<b1._realPath<<"不存在"<<std::endl;
                }
                std::cout<<__LINE__<<" "<<b1._realPath<<std::endl;
                std::cout<<__LINE__<<" "<<b1._compressPath<<std::endl;
                remove(b1._compressPath.c_str());
                // 更新备份信息
                b1._compressFlag = false;
            }
                    b1._aTime = time(nullptr);
            user.data->update(b1);

            if (!fileUtil(b1._realPath).exists())
            {
                res.status = 404;
                std::cout<<__LINE__<<"出现404"<<std::endl;

                return;
            }
            // 4. 检测请求中是否包含If-Range字段,并且If-Range字段的值是否是==NewEtag
            if (req.has_header("If-Range") && req.get_header_value("If-Range") == getETag(b1))
            {
                // 5. 构建响应
                // 由于httplib支持了区间读写,我们直接使用库里面的
                fileUtil f3(b1._realPath);
                f3.getContent(&res.body);
                res.status = 206;
                res.set_header("Content-Type", "application/octet-stream");
                res.set_header("Accept-Ranges", "bytes");
                res.set_header("ETag", getETag(b1));
            }
            else
            {
                // 5. 构建响应
                fileUtil f3(b1._realPath);
                f3.getContent(&res.body);
                res.status = 200;
                res.set_header("Content-Type", "application/octet-stream");
                res.set_header("Accept-Ranges", "bytes");
                res.set_header("ETag", getETag(b1));
            }
            
        
        }
        static void LoginShow(const httplib::Request &req, httplib::Response &res)
        {
            std::fstream fin("login.html", std::fstream::in);
            std::string body;
            while (true)
            {
                std::getline(fin, body);
                if (fin.eof())
                    break;
                res.body += body;
            }
            res.status = 200;
            res.set_header("Content-Type", "text/html");
        }

    public:
        Server()
        {
            // 完成方法注册
            // 1.Post /login/login/或/login/enroll/ 登录或注册请求
            _httpLibServer.Post("/login/(.*)/", LoginFun);
            // 2.Post /backup/username/ 备份请求
            _httpLibServer.Post("/backup/", BackupFun);
            // 3.Get /showList/username/ 展示请求
            _httpLibServer.Get("/showList/", ShowListFun);
            // 4. /download/username/xxxx 下载请求
            _httpLibServer.Get(Config::getInstance().urlPrefix() + "(.*)", DownloadFun);
            _httpLibServer.Get("/", LoginShow);
             pid_t id = fork();
             if (id > 0 || id < 0)
                 exit(-1);
             setsid();
             int fd = open("/dev/null", O_WRONLY | O_RDONLY);
             dup2(fd, 0);
             dup2(fd, 1);
             dup2(fd, 2);
             close(fd);
        }

    public:
        void operator()()
        {
            if (!_httpLibServer.listen("0.0.0.0", Config::getInstance().serverPort()))
                exit(-1);
        }

    private:
        httplib::Server _httpLibServer;
    };
}
